﻿using System;
using Csla;
using System.ComponentModel.DataAnnotations;
using BizControl.Resources;
using BizControl.DalLinq;
using BizControl.Library.BusinessObjects.People;
using Csla.Data;
using System.Data.Linq;
using BizControl.Library.Security;

namespace BizControl.Library.BusinessObjects.Activities
{
  [Serializable()]
  public class ActivityLinkBO : BusinessBase<ActivityLinkBO>
  {
    #region Business Methods

    private static readonly PropertyInfo<ActivityInfo> Activity1Property = RegisterProperty<ActivityInfo>(c => c.Activity1);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"ActivityRequiredPropertyError")]
    public ActivityInfo Activity1
    {
      get { return GetProperty(Activity1Property); }
      private set { SetProperty(Activity1Property, value); }
    }

    private static readonly PropertyInfo<ActivityInfo> Activity2Property = RegisterProperty<ActivityInfo>(c => c.Activity2);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"ActivityRequiredPropertyError")]
    public ActivityInfo Activity2
    {
      get { return GetProperty(Activity2Property); }
      private set { SetProperty(Activity2Property, value); }
    }

    private static readonly PropertyInfo<string> ConditionProperty = RegisterProperty<string>(c => c.Condition);
    [Display(ResourceType = typeof(PropertiesNames), Name = @"ConditionProperty")]
    public string Condition
    {
      get { return GetProperty(ConditionProperty); }
      set { SetProperty(ConditionProperty, value); }
    }

    private static readonly PropertyInfo<string> CommentProperty = RegisterProperty<string>(c => c.Comment);
    [Display(ResourceType = typeof(PropertiesNames), Name = @"CommentProperty")]
    public string Comment
    {
      get { return GetProperty(CommentProperty); }
      set { SetProperty(CommentProperty, value); }
    }

    #region Common properties

    private static readonly PropertyInfo<bool> IsDeletedFieldProperty = RegisterProperty<bool>(c => c.IsDeletedField, null, false);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"IsDeletedRequiredError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"IsDeletedFieldProperty")]
    public bool IsDeletedField
    {
      get { return GetProperty(IsDeletedFieldProperty); }
      private set { SetProperty(IsDeletedFieldProperty, value); }
    }

    private static readonly PropertyInfo<PersonInfo> CreatedByProperty = RegisterProperty<PersonInfo>(c => c.CreatedBy);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"CreatedByRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"CreatedByProperty")]
    public PersonInfo CreatedBy
    {
      get { return GetProperty(CreatedByProperty); }
      private set { SetProperty(CreatedByProperty, value); }
    }

    private static readonly PropertyInfo<DateTime> CreatedOnProperty = RegisterProperty<DateTime>(c => c.CreatedOn);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"CreatedOnRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"CreatedOnProperty")]
    public DateTime CreatedOn
    {
      get { return GetProperty(CreatedOnProperty); }
      private set { SetProperty(CreatedOnProperty, value); }
    }

    private static readonly PropertyInfo<DateTime> LastChangedProperty = RegisterProperty<DateTime>(c => c.LastChanged);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"LastChangedRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"LastChangedProperty")]
    public DateTime LastChanged
    {
      get { return GetProperty(LastChangedProperty); }
      private set { SetProperty(LastChangedProperty, value); }
    }

    private static readonly PropertyInfo<PersonInfo> LastChangedByProperty = RegisterProperty<PersonInfo>(c => c.LastChangedBy);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"LastChangedByRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"LastChangedByProperty")]
    public PersonInfo LastChangedBy
    {
      get { return GetProperty(LastChangedByProperty); }
      private set { SetProperty(LastChangedByProperty, value); }
    }

    private static readonly PropertyInfo<byte[]> TimeStampProperty = RegisterProperty<byte[]>(c => c.TimeStamp);
    private byte[] TimeStamp
    {
      get { return GetProperty(TimeStampProperty); }
      set { SetProperty(TimeStampProperty, value); }
    }

    #endregion

    #region Methods

    #endregion

    internal void LoadData(ActivityLink linkDB)
    {
      if (linkDB == null) return;
      Activity1 = new ActivityInfo(linkDB.Activity1Ref);
      Activity2 = new ActivityInfo(linkDB.Activity2Ref);
      Condition = linkDB.Condition;
      Comment = linkDB.Comment;

      // Common properties
      CreatedBy = new PersonInfo(linkDB.CreatedByRef);
      LastChangedBy = new PersonInfo(linkDB.LastChangedByRef);

      CreatedOn = linkDB.CreatedOn;
      LastChanged = linkDB.LastChanged;

      IsDeletedField = linkDB.IsDeleted;
      TimeStamp = linkDB.TimeStamp.ToArray();
    }

    #endregion

    #region Business Rules

    protected override void AddBusinessRules()
    {
      base.AddBusinessRules();
    }

    #endregion

    #region  Data Access

    private void Child_Create(ActivityBO activity1, ActivityBO activity2, ActivityLinkType type)
    {
      if (activity1 == null || activity1.IsEmpty()
        || activity2 == null || activity2.IsEmpty()) throw new ArgumentNullException(ExceptionsMessages.ActivityNullReference);
      var currentUser = SecurityChecks.GetCurrentUser();
      using (BypassPropertyChecks)
      {
        Activity1 = new ActivityInfo(activity1);
        Activity2 = new ActivityInfo(activity2);
        Condition = type.ToString();
        CreatedBy = new PersonInfo(currentUser);
        LastChangedBy = new PersonInfo(currentUser);
        CreatedOn = DateTime.Now;
      }
      base.Child_Create();
    }

    private void Child_Fetch(ActivityLink data, ActivityBO activity1)
    {
      if (activity1 == null || activity1.IsEmpty()) throw new ArgumentNullException(ExceptionsMessages.ActivityNullReference);
      using (BypassPropertyChecks)
      {
        LoadData(data);
      }
    }

    private void Child_Insert()
    {
      using (var ctx = ContextManager<BusinessControl2DataContext>.GetManager(Database.BizControlDB))
      {
        Binary lastTimeStamp = null;
        LastChanged = DateTime.Now;
        using (BypassPropertyChecks)
        {
          ctx.DataContext.AddActivityLink(
            Activity1 == null || Activity1.IsEmpty() ? (Guid?)null : Activity1.Id,
            Activity2 == null || Activity2.IsEmpty() ? (Guid?)null : Activity2.Id,
            Condition,
            Comment,
            IsDeletedField,
            CreatedBy == null || CreatedBy.IsEmpty() ? (Guid?)null : CreatedBy.Id,
            CreatedOn,
            LastChanged,
            LastChangedBy == null || LastChangedBy.IsEmpty() ? (Guid?)null : LastChangedBy.Id,
            ref lastTimeStamp);
          TimeStamp = lastTimeStamp.ToArray();
        }
      }
    }

    private void Child_Update()
    {
      using (var ctx = ContextManager<BusinessControl2DataContext>.GetManager(Database.BizControlDB))
      {
        if (IsSelfDirty)
        {
          Binary lastTimeStamp = null;
          LastChangedBy = new PersonInfo(SecurityChecks.GetCurrentUser());
          LastChanged = DateTime.Now;
          using (BypassPropertyChecks)
          {
            ctx.DataContext.UpdateActivityLink(
              Activity1 == null || Activity1.IsEmpty() ? (Guid?)null : Activity1.Id,
              Activity2 == null || Activity2.IsEmpty() ? (Guid?)null : Activity2.Id,
              Condition,
              Comment,
              IsDeletedField,
              LastChanged,
              LastChangedBy == null || LastChangedBy.IsEmpty() ? (Guid?)null : LastChangedBy.Id,
              TimeStamp,
              ref lastTimeStamp);
            TimeStamp = lastTimeStamp.ToArray();
          }
        }
      }
    }

    private void Child_DeleteSelf()
    {
      using (BypassPropertyChecks)
      {
        IsDeletedField = true;
        Child_Update();
      }
    }

    #endregion

    #region  Factory Methods

    internal static ActivityLinkBO NewActivityLink(ActivityBO activity1, ActivityBO activity2, ActivityLinkType type)
    {
      return Csla.DataPortal.CreateChild<ActivityLinkBO>(activity1, activity2, type);
    }

    internal static ActivityLinkBO GetActivityLink(ActivityLink data, ActivityBO activity1)
    {
      return Csla.DataPortal.FetchChild<ActivityLinkBO>(data, activity1);
    }

    private ActivityLinkBO()
    { /* require use of factory methods */ }

    #endregion

  }
}
